#ifndef _GameObject_H
#define _GameObject_H

#include <string>
#include <map>

#include "AttributeComponent.h"
#include "BehaviourComponent.h"

#include "Logger.h"
#include "StringUtils.h"

#ifdef GALLIUMENGINE_DLL 
#define GALLIUMENGINE_API __declspec( dllexport )
#else
#define GALLIUMENGINE_API __declspec( dllimport )
#endif

namespace GalliumEngine
{

	class GameObject
	{
	private:
		std::string m_id;
	
		typedef std::map<std::string,BehaviourComponent*> BehaviourComponentMap;
		typedef BehaviourComponentMap::iterator BehaviourComponentItr;
		typedef BehaviourComponentMap::const_iterator BehaviourComponentConstItr;
		typedef std::pair<std::string,BehaviourComponent*> BehaviourComponentPair;

		typedef std::map<std::string,AttributeComponent*> AttributeComponentMap;
		typedef AttributeComponentMap::iterator AttributeComponentItr;
		typedef AttributeComponentMap::const_iterator AttributeComponentConstItr;
		typedef std::pair<std::string,AttributeComponent*> AttributeComponentPair;

		BehaviourComponentMap m_behaviourComponents;
		AttributeComponentMap m_attributeComponents;
	public:

		/// <summary>Create a new GameObject.</summary>
		GALLIUMENGINE_API GameObject(void);

		/// <summary>Destroy the GameObject.</summary>
		GALLIUMENGINE_API ~GameObject(void);

		/// <summary>Sets the GameObject Id.</summary>
		/// <param type="std::string" name="id">The id to set.</param>
		GALLIUMENGINE_API void setId(std::string);

		/// <summary>Gets the GameObject Id.</summary>
		/// <returns>The id of the GameObject<returns>
		GALLIUMENGINE_API std::string getId();

		/// <summary>Add a BehaviourComponent to the GameObject.</summary>
		/// <param type="BehaviourComponent*" name="component">A pointer to the BehaviourComponent.</param>
		/// <returns>Whether the BehaviourComponent was added.<returns>
		GALLIUMENGINE_API bool addBehaviourComponent(BehaviourComponent*);

		/// <summary>Remove a BehaviourComponent from the GameObject.</summary>
		/// <param type="std::string" name="id">The id to remove.</param>
		/// <returns>Whether the BehaviourComponent was removed.<returns>
		GALLIUMENGINE_API bool removeBehaviourComponent(std::string);

		/// <summary>Gets a BehaviourComponent from the GameObject.</summary>
		/// <param type="std::string" name="id">The id to get.</param>
		/// <returns>The BehaviourComponent.<returns>
		GALLIUMENGINE_API BehaviourComponent* getBehaviourComponent(std::string);

		/// <summary>Add a AttributeComponent to the GameObject.</summary>
		/// <param type="AttributeComponent*" name="component">A pointer to the AttributeComponent.</param>
		/// <returns>Whether the AttributeComponent was added.<returns>
		GALLIUMENGINE_API bool addAttributeComponent(AttributeComponent*);

		/// <summary>Remove a AttributeComponent from the GameObject.</summary>
		/// <param type="std::string" name="id">The id to remove.</param>
		/// <returns>Whether the AttributeComponent was removed.<returns>
		GALLIUMENGINE_API bool removeAttributeComponent(std::string);

		/// <summary>Gets a AttributeComponent from the GameObject.</summary>
		/// <param type="std::string" name="id">The id to get.</param>
		/// <returns>The AttributeComponent.<returns>
		GALLIUMENGINE_API AttributeComponent* getAttributeComponent(std::string);

		/// <summary>Initialize the GameObject and all child Components.</summary>
		GALLIUMENGINE_API void initialize();

		/// <summary>Deinitialize the GameObject and all child Components.</summary>
		GALLIUMENGINE_API void deinitialize();

		/// <summary>Updates all BehaviourComponents that require it.</summary>
		GALLIUMENGINE_API void update(float);

		/// <summary>Renders all BehaviourComponents that require it.</summary>
		GALLIUMENGINE_API void render();
	};

}

#endif

